<html>
    <head>
        <meta charset="utf-8">
        <script type="text/javascript" src="lib/require.js"></script>
        <script type="text/javascript" src="lib/dat.gui.js"></script>
        <script type="text/javascript" src="lib/stats.js"></script>
    </head>
    <body style="margin:0px;">
        <canvas width="1200" height="640" id="Main"></canvas>
        <script type="text/javascript">
            require([
                '../dist/claygl',
                'js/createDOFCompositor'
            ], function(clay, createDOFCompositor){
                var renderer = new clay.Renderer({
                    canvas: document.getElementById('Main'),
                    devicePixelRatio: 1
                });
                renderer.resize(window.innerWidth, window.innerHeight);
                var camera = new clay.camera.Perspective({
                    aspect: renderer.getViewportAspect()
                });
                camera.position.set(0, 0.5, 3);
                camera.lookAt(clay.Vector3.ZERO);

                var scene = new clay.Scene();
                var rootNode = new clay.Node();
                scene.add(rootNode);
                scene.add(camera);

                var dirLight = new clay.light.Directional({
                    intensity: 0.5
                });
                dirLight.position.set(1, 1, 1);
                dirLight.lookAt(clay.Vector3.ZERO);
                scene.add(dirLight);

                var loader = new clay.loader.GLTF({
                    rootNode: rootNode
                });
                loader.load('assets/models/basic_scene/scene.gltf');
                var control = new clay.plugin.OrbitControl({
                    target: camera,
                    domElement: renderer.canvas
                });

                var sphereGeo = new clay.geometry.Sphere({
                    radius: 0.2
                });
                for (var i = 0; i < 100; i++) {
                    var emitMesh = new clay.Mesh({
                        material: new clay.Material({
                            shader: clay.shader.library.get('clay.standard')
                        }),
                        geometry: sphereGeo
                    });
                    emitMesh.position.set(Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50);
                    emitMesh.material.set('emission', [Math.random(), Math.random(), Math.random()]);
                    emitMesh.material.set('emissionIntensity', 5);
                    emitMesh.material.set('color', [0, 0, 0]);
                    emitMesh.material.set('specularColor', [0, 0, 0]);

                    scene.add(emitMesh);
                }
                loader.on('success', function(res) {

                    rootNode.rotation.rotateX(-Math.PI / 2);

                    var envMap = clay.util.texture.loadTexture(
                        'assets/textures/hdr/pisa.hdr',
                        {
                            exposure: 3
                        },
                        function () {
                            envMap.flipY = false;
                            var prefilterResult = clay.util.cubemap.prefilterEnvironmentMap(
                                renderer, envMap, {
                                    width: 128,
                                    height: 128
                                }
                            );
                            var suzanneMesh = scene.getNode('Suzanne');
                            suzanneMesh.material.set('metalness', 1);
                            suzanneMesh.material.set('color', [1, 1, 1]);
                            // var skydome = new clay.plugin.Skydome({
                            //     scene: scene
                            // });
                            // skydome.material.set('diffuseMap', envMap);

                            rootNode.traverse(function (mesh) {
                                if (mesh.isRenderable()) {
                                    mesh.material.set('maxMipmapLevel', prefilterResult.maxMipmapLevel - 2);
                                    mesh.material.set('brdfLookup', prefilterResult.brdfLookup);
                                    mesh.material.set('environmentMap', prefilterResult.environmentMap);
                                    mesh.material.set('roughness', 0.2);

                                    mesh.material.define('ENVIRONMENTMAP_PREFILTER');
                                    mesh.material.define('USE_METALNESS');
                                    mesh.material.define('USE_ROUGHNESS');
                                    mesh.material.define('SRGB_DECODE');
                                    mesh.material.define('RGBM_ENCODE');

                                }
                            });
                        }
                    );


                    var compositor = createDOFCompositor(renderer, scene, camera);
                    var blurNodes = compositor.getBlurNodes();
                    var cocNode = compositor.getNodeByName('coc');
                    var dofCompositeNode = compositor.getNodeByName('dof_composite');
                    var compositeNode = compositor.getNodeByName('composite');

                    var timeline =  new clay.Timeline();
                    timeline.start();
                    timeline.on('frame', function(deltaTime) {
                        control.update(deltaTime);

                        compositor.render(renderer);
                        // renderer.render(scene, camera);

                        stats.update();
                    });

                    //--------------------
                    // Config GUI
                    //--------------------
                    var gui = new dat.GUI();
                    var config = {
                        blurSize: 1,
                        focalDist: 4,
                        focalRange: 0.2,
                        fstop: 1.4,
                        debug: 'none'
                    };

                    function updateParameters() {
                        for (var i = 0; i < blurNodes.length; i++) {
                            blurNodes[i].setParameter('blurSize', config.blurSize);
                        }

                        cocNode.setParameter('focalDist', config.focalDist);
                        cocNode.setParameter('fstop', config.fstop);
                        cocNode.setParameter('focalRange', config.focalRange);
                        dofCompositeNode.setParameter('textureSize', [renderer.getWidth(), renderer.getHeight()]);
                        dofCompositeNode.setParameter('blurredSize', [renderer.getWidth() / 2, renderer.getHeight() / 2]);

                    }

                    function updateDebugConfig() {
                        if (config.debug === 'COC' || config.debug === 'Near COC') {
                            dofCompositeNode.pass.material.undefine('RGBM');
                            compositeNode.pass.material.undefine('RGBM_DECODE');
                            compositeNode.pass.material.define('DEBUG', 1);
                        }
                        else {
                            dofCompositeNode.pass.material.define('RGBM');
                            compositeNode.pass.material.define('RGBM_DECODE');

                            compositeNode.pass.material.define('DEBUG', 0);
                        }
                        dofCompositeNode.pass.material.define('DEBUG', debugConfigValueMap[config.debug]);
                    }

                    var debugConfigs = ['none', 'COC', 'Near COC', 'Blurred', 'Blurred Near'];
                    var debugConfigValueMap = debugConfigs.reduce(function (obj, val, idx) {
                        obj[val] = idx;
                        return obj;
                    }, {});

                    gui.add(config, 'blurSize', 0, 4).onChange(updateParameters);
                    gui.add(config, 'fstop', 0.2, 8).onChange(updateParameters);
                    gui.add(config, 'focalDist', 0.1, 8).onChange(updateParameters);
                    gui.add(config, 'focalRange', 0, 1).onChange(updateParameters);
                    gui.add(config, 'debug', debugConfigs).onChange(updateDebugConfig);

                    updateParameters();
                });


                var stats = new Stats();
                stats.domElement.style.position = 'absolute';
                stats.domElement.style.top = '0px';
                stats.domElement.style.left = '0px';
                document.body.appendChild(stats.domElement);
            });

        </script>
    </body>
</html>